package edu.iscas.xcheck.analysis.dom.model;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import edu.iscas.xcheck.analysis.dom.visitors.DomVisitor;

public class DomNode {

	private int type;
	private String tagName, xpath, text, id, nodeid, pid, order;
	private Map<String, String> attributes;
	private int zindex, level;
	private int[] coord;

	private int clickable, visible;
	private boolean matched;

	private List<DomNode> children;
	private DomNode parent;

	// Constructors

	public DomNode(String tagName, String xPath) {
		this.setTagName(tagName);
		this.setNodeType(1);
		this.setxPath(xPath);
		this.setAttributes(new HashMap<String, String>());
	}

	public DomNode(String text) {
		try {
			this.setText(URLDecoder.decode(text, "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			System.err.println("Node text cannot be decoded :" + text);
			e.printStackTrace();
		}
		this.setNodeType(0);
	}

	// Accept Visitors

//	public void accept(DomVisitor visitor, boolean tagNodesOnly) {
//		visitor.visit(this);
//
//		for (DomNode child : this.children) {
//			if (child.nodeType == NodeType.TAG || !tagNodesOnly) {
//				child.accept(visitor, tagNodesOnly);
//			}
//		}
//
//		visitor.endVisit(this);
//	}

	public void accept(DomVisitor visitor) {
		visitor.visit(this);
	}

	// Setters & Getters

	public String attr(String key) {
		return this.attributes.get(key);
	}

	public int getNodeType() {
		return type;
	}

	private void setNodeType(int nodeType) {
		this.type = nodeType;
	}

	public String getTagName() {
		if (tagName == null) {
			setTagOrder(this.xpath);
		}
		return tagName;
	}

	private void setTagName(String tagName) {
		this.tagName = tagName;
	}

	public String getxPath() {
		return xpath;
	}

	public void setxPath(String xPath) {
		this.xpath = xPath;
	}

	public String getText() {
		return text;
	}

	private void setText(String text) {
		this.text = text;
	}

	public String getId() {
		return id;
	}

	public Map<String, String> getAttributes() {
		return attributes;
	}

	private void setAttributes(Map<String, String> attributes) {
		this.attributes = attributes;
	}

	public int getZindex() {
		return zindex;
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
	}

	public void setCoord(int[] coord) {
		this.coord = coord;
	}

	public int[] getCoords() {
		return coord;
	}

	public String getHash() {
		return getNodeid();
	}

	public int isClickable() {
		return clickable;
	}

	public int isVisible() {
		return visible;
	}

	public boolean isMatched() {
		return matched;
	}

	public void setMatched(boolean matched) {
		this.matched = matched;
	}

	public List<DomNode> getChildren() {
		return children;
	}

	public void setChildren(List<DomNode> children) {
		this.children = children;
	}

	public DomNode getParent() {
		return parent;
	}

	public void setParent(DomNode parent) {
		this.parent = parent;
	}
	
	// Utility Methods

	public boolean isTag() {
		return (type == 1);
	}

	public boolean isText() {
		return (type == 0);
	}

	@Override
	public String toString() {
		return tagName + " > " + xpath + "{txt=" + text + "}" + attributes;
	}

	public Map<String, String> getDynDomData() {
		Map<String, String> domData = new HashMap<>();
		domData.put("clickable", isClickable() == 1 ? "t" : "f");
		domData.put("visible", isVisible() == 1 ? "t" : "f");
		if (zindex != Integer.MIN_VALUE) {
			domData.put("zindex", String.format("%d", zindex));
		}
		if(children != null){
			domData.put("children", String.format("%d", children.size()));
		}
		return domData;
	}

	private String parseTagName(String xPath) {
		if (xPath == null) {
			return null;
		} else {
			String[] tags = xPath.split("/");
			if (tags.length > 0) {
				return tags[tags.length - 1].replaceAll("\\[[0-9]*\\]", "");
			}
			return null;
		}
	}

	private void setTagOrder(String xPath) {
		String tag = "", order = "0";
		int tagBegin = xPath.lastIndexOf("/");
		if (tagBegin != -1) {
			int orderBegin = xPath.indexOf("[", tagBegin);
			if (orderBegin != -1) {
				tag = xPath.substring(tagBegin + 1, orderBegin);
				order = xPath.substring(orderBegin + 1, xPath.length() - 1);
			} else {
				tag = xPath.substring(tagBegin + 1);
			}
		}
		this.tagName = tag;
		this.order = order;
	}

	public String getNodeid() {
		return nodeid;
	}

	public String getPid() {
		return pid;
	}

	public String getOrder() {
		if (order == null) {
			setTagOrder(this.xpath);
		}
		return order;
	}

	public void setOrder(String order) {
		this.order = order;
	}

	// public void accept(ApproxMatchVisitor amv) {
	// // TODO Auto-generated method stub
	//
	// }

}
